home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD 2.1 / Amiga Developer CD v2.1.iso / Reference / DevCon / Milan_1991 / Devcon91.4 / AppShell / Examples / MultiProj / multiproj.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-09-01  |  21.1 KB  |  817 lines

  1. /************************************************************************
  2.  *                                                                      *
  3.  *                            Preliminary                               *
  4.  *                        Amiga AppShell (tm)                           *
  5.  *                                                                      *
  6.  *  Copyright (c) 1990,1991 Commodore-Amiga, Inc. All Rights Reserved.  *
  7.  *                                                                      *
  8.  *   This software and information is proprietary, preliminary, and     *
  9.  *   subject to change without notice.                                  *
  10.  *                                                                      *
  11.  *                            DISCLAIMER                                *
  12.  *                                                                      *
  13.  *   THIS SOFTWARE IS PROVIDED "AS IS".                                 *
  14.  *   NO REPRESENTATIONS OR WARRANTIES ARE MADE WITH RESPECT TO THE      *
  15.  *   ACCURACY, RELIABILITY, PERFORMANCE, CURRENTNESS, OR OPERATION      *
  16.  *   OF THIS SOFTWARE, AND ALL USE IS AT YOUR OWN RISK.                 *
  17.  *   NEITHER COMMODORE NOR THE AUTHORS ASSUME ANY RESPONSIBILITY OR     *
  18.  *   LIABILITY WHATSOEVER WITH RESPECT TO YOUR USE OF THIS SOFTWARE.    *
  19.  *                                                                      *
  20.  *                          Non-Disclosure                              *
  21.  *                                                                      *
  22.  *   This information is not to be disclosed to any other company,      *
  23.  *   individual or party.  Discussion is to be restricted to CBM        *
  24.  *   approved discussion areas, such as the closed conferences on bix;  *
  25.  *   amiga.cert, amiga.com, amiga.beta/appshell.                        *
  26.  *                                                                      *
  27.  ************************************************************************
  28.  * multiproj.c
  29.  * Copyright (C) 1991 Commodore-Amiga, Inc.
  30.  * Minimum requirements for an AppShell application.
  31.  * Written by David N. Junod
  32.  *
  33.  * Must be compiled with Lattice options: -b0 -cfist -ms -v
  34.  *
  35.  */
  36.  
  37. #include "multiproj.h"
  38. #include "multiproj_rev.h"
  39.  
  40. #define    DI(x)    ;
  41.  
  42. void kprintf(void *, ...);
  43.  
  44. /* Private functions */
  45. BOOL start_project (struct AppInfo * ai, struct ProjNode * pn);
  46. VOID signal_projects (struct AppInfo *, LONG, VOID (*func) (struct AppInfo *, struct ProjData *));
  47. BOOL SafePutToPort (struct Message * message, STRPTR name);
  48.  
  49. /* Shell argument template */
  50. #define TEMPLATE "Files/M,BG=Background/S,UnLoad/S"
  51. #define    OPT_FILES    0
  52. #define    OPT_BACKG    1
  53. #define OPT_UNLOAD    2
  54. #define    OPT_COUNT    3
  55.  
  56. /* All text used in the application must be defined in a text array.  Then
  57.  * referred to by numeric ID. */
  58. STRPTR MasterText[] =
  59. {
  60.  /* Padding */
  61.     "",
  62.  
  63.     "Not enough memory",
  64.     "Couldn't allocate project",
  65.     "Couldn't start project process",
  66.     "Master port went away",
  67.     "Can't allocate images",
  68.  
  69.  /* NULL termination is required */
  70.     NULL
  71. };
  72.  
  73. #define    MPERR_NO_MEMORY        1
  74. #define    MPERR_NO_PROJECT    2
  75. #define    MPERR_NO_PROCESS    3
  76. #define    MPERR_NO_PORT        4
  77.  
  78. /* The AppShell will convert this array into function table entries and will
  79.  * add them to the function table list.  Using the APSHF_PRIVATE flag, we are
  80.  * able to have functions that can't be triggered by the user.  This
  81.  * also defines the commands that are available through ARexx.  Note that
  82.  * the command parser is case-INSENSITIVE, but for readability, your
  83.  * entries in this table should follow standard capitalization rules. */
  84. struct Funcs MasterFuncTable[] =
  85. {
  86.  /* These are public master functions */
  87.     {"Quit", QuitFunc, QuitID, "FORCE/S,UNLOAD/S", 2L, NULL,},
  88.     {"New", NewFunc, NewID,},
  89.  
  90.  /* This function can not be accessed by the user */
  91.     {"CInit", CInitFunc, CInitID, NULL, NULL, APSHF_PRIVATE},
  92.     {"CExit", CExitFunc, CExitID, NULL, NULL, APSHF_PRIVATE},
  93.     {"IsActive", IsActiveFunc, IsActiveID, NULL, NULL, APSHF_PRIVATE},
  94.     {"Open", OpenFunc, OpenID, NULL, NULL, APSHF_PRIVATE,},
  95.     {"Close", CloseFunc, CloseID, NULL, NULL, APSHF_PRIVATE,},
  96.     {"ActiveTool", ActiveToolFunc, ActiveToolID, NULL, NULL, APSHF_PRIVATE,},
  97.     {"SetAttrs", SetAttrsFunc, SetAttrsID, "BACKGROUND/S,UNLOAD/S", 2, NULL,},
  98.  
  99.  /* Marks the end of the array */
  100.     {NULL, NO_FUNCTION,}
  101. };
  102.  
  103. /* Shared system libraries */
  104. struct Library *AslBase;
  105. struct Library *GadToolsBase;
  106. struct Library *GfxBase;
  107. struct Library *IconBase;
  108. struct Library *IntuitionBase;
  109. struct Library *UtilityBase;
  110. struct Library *AppObjectsBase;
  111.  
  112. /* Library Environment:
  113.  * This tag array is used to open and close the shared system libraries
  114.  * needed by our application.
  115.  */
  116. struct TagItem Our_Libs[] =
  117. {
  118.  /* Minimum library version */
  119.     {APSH_LibVersion, 36L},
  120.  
  121.  /* All libraries are required */
  122.     {APSH_LibStatus, APSH_REQUIRED},
  123.  
  124.  /* Libraries to open */
  125.     {APSH_ASL, (ULONG) & AslBase},
  126.     {APSH_GadTools, (ULONG) & GadToolsBase},
  127.     {APSH_Gfx, (ULONG) & GfxBase},
  128.     {APSH_Icon, (ULONG) & IconBase},
  129.     {APSH_Intuition, (ULONG) & IntuitionBase},
  130.     {APSH_Utility, (ULONG) & UtilityBase},
  131.  
  132.  /* The next library is optional */
  133.     {APSH_LibStatus, APSH_OPTIONAL},
  134.     {APSH_LibName, (ULONG) "appobjects.library"},
  135.     {APSH_LibBase, (ULONG) & AppObjectsBase},
  136.     {TAG_DONE,}
  137. };
  138.  
  139.  /* ARexx user interface environment specification array */
  140. static struct TagItem Handle_AREXX[] =
  141. {
  142.     {APSH_Extens, (ULONG) "skel"},
  143.     {APSH_Status, APSHP_SINGLE},
  144.     {APSH_Rating, APSH_OPTIONAL},
  145.     {TAG_DONE,}
  146. };
  147.  
  148. /* These tags describe the Simple IPC user interface. */
  149. static struct TagItem Handle_SIPC[] =
  150. {
  151.     {APSH_Status, APSHP_SINGLE},
  152.     {APSH_Rating, APSH_REQUIRED},
  153.     {APSH_AlreadyRunning, IsActiveID},
  154.     {TAG_DONE,}
  155. };
  156.  
  157. /* These tags describe the Asynchronous Tool user interface */
  158. struct TagItem Handle_Tool[] =
  159. {
  160.     {APSH_Rating, APSH_REQUIRED},
  161.     {TAG_DONE,}
  162. };
  163.  
  164. /* Application Environment:
  165.  * Tell about the master server application */
  166. struct TagItem Our_App[] =
  167. {
  168.  /* About the application */
  169.     {APSH_AppName, (ULONG) APPNAME},
  170.     {APSH_AppVersion, (ULONG) APPVERS},
  171.     {APSH_AppCopyright, (ULONG) APPCOPY},
  172.     {APSH_AppAuthor, (ULONG) APPAUTH},
  173.  
  174.  /* Trigger the library opening module */
  175.     {APSH_OpenLibraries, (ULONG) Our_Libs},
  176.  
  177.  /* Specify the application function table */
  178.     {APSH_FuncTable, (ULONG) MasterFuncTable},
  179.  
  180.  /* Specify the application text table */
  181.     {APSH_DefText, (ULONG) MasterText},
  182.  
  183.  /* Tell how memory we need for our own data */
  184.     {APSH_UserDataSize, sizeof (struct MasterData)},
  185.  
  186.  /* Give our Shell startup argument template */
  187.     {APSH_Template, (ULONG) TEMPLATE},
  188.     {APSH_NumOpts, (ULONG) OPT_COUNT},
  189.  
  190.  /* Must always specify the SIPC user interface */
  191.     {APSH_AddSIPC_UI, (ULONG) Handle_SIPC},
  192.  
  193.  /* Add the Asynchronous tool user interface */
  194.     {APSH_AddTool_UI, (ULONG) Handle_Tool},
  195.  
  196.  /* Add an ARexx user interface */
  197.     {APSH_AddARexx_UI, (ULONG) Handle_AREXX},
  198.  
  199.  /* Specify a custom initialization routine */
  200.     {APSH_AppInit, CInitID},
  201.     {APSH_AppExit, CExitID},
  202.  
  203.     {TAG_DONE,}
  204. };
  205.  
  206. /* handle messages between function handlers */
  207. BOOL HandlerFunc (struct AppInfo * ai, ULONG tags,...)
  208. {
  209.     return (HandlerFuncA (ai, (struct TagItem *) & tags));
  210. }
  211.  
  212. /* get handler data */
  213. APTR HandlerData (struct AppInfo * ai, ULONG tags,...)
  214. {
  215.     return (HandlerDataA (ai, (struct TagItem *) & tags));
  216. }
  217.  
  218. /* This is the initialization routine for the master server for the
  219.  * application. */
  220. VOID CInitFunc (struct Hook *h, struct AppInfo *ai, struct AppFunction *af)
  221. {
  222.     struct MasterData *md = (struct MasterData *) ai->ai_UserData;
  223.     struct Project *p = &(ai->ai_Project);
  224.     struct List *list = &(p->p_ProjList);
  225.     struct ProjNode *pn = NULL;
  226.     struct MsgHandler *mh;
  227.  
  228.     /* Check the options */
  229.     DI (kprintf ("CInitFunc enter\n"));
  230.     if (ai->ai_Options[OPT_BACKG])
  231.     {
  232.     md->md_Flags |= MADF_BACKG;
  233.     }
  234.     if (ai->ai_Options[OPT_UNLOAD])
  235.     {
  236.     md->md_Flags &= ~MADF_BACKG;
  237.     }
  238.  
  239.     /* Get a handle on our SIPC port */
  240.     if (mh = HandlerData (ai, APSH_Handler, "SIPC", TAG_DONE))
  241.     {
  242.     /* Cache the pointer */
  243.     md->md_SIPC = mh->mh_Port;
  244.     }
  245.  
  246.     /* Make sure there are entries in the project list */
  247.     if (list->lh_TailPred != (struct Node *) list)
  248.     {
  249.     struct Node *node, *nxtnode;
  250.  
  251.     /* Let's start at the very beginning... */
  252.     node = list->lh_Head;
  253.  
  254.     /* Continue while there are still nodes */
  255.     while ((ai->ai_Pri_Ret == RETURN_OK) &&
  256.            ((nxtnode = node->ln_Succ)))
  257.     {
  258.         /* Start the project */
  259.         start_project (ai, (struct ProjNode *) node);
  260.  
  261.         /* Go on to the next node */
  262.         node = nxtnode;
  263.     }
  264.     }
  265.     /*
  266.      * No FILES/M parameters specified, see if they just want to load us in the
  267.      * background.
  268.      */
  269.     else if (!(ai->ai_Options[OPT_BACKG]))
  270.     {
  271.     /* They want an new, blank project to work with. */
  272.     if (pn = NewProject (ai, NULL, NULL))
  273.     {
  274.         /* Start the project */
  275.         start_project (ai, pn);
  276.     }
  277.     /* Unable to allocate a new project */
  278.     else
  279.     {
  280.         ai->ai_Pri_Ret = RETURN_FAIL;
  281.         ai->ai_Sec_Ret = MPERR_NO_PROJECT;
  282.         ai->ai_TextRtn =
  283.           PrepText (ai, APSH_USER_ID, ai->ai_Sec_Ret, NULL);
  284.     }
  285.     }
  286.     else
  287.     {
  288.     }
  289.     DI (kprintf ("CInitFunc exit\n"));
  290. }
  291.  
  292. VOID CExitFunc (struct Hook *h, struct AppInfo *ai, struct AppFunction *af)
  293. {
  294.     /* We don't really do anything in this example */
  295. }
  296.  
  297.  /* Open existing project */
  298. VOID OpenFunc (struct Hook *h, struct AppInfo *ai, struct AppFunction *af)
  299. {
  300.     struct Project *p = &(ai->ai_Project);
  301.     struct List *list = &(p->p_ProjList);
  302.     struct TagItem *attrs = af->af_Attrs;
  303.     struct ProjNode *pn = NULL;
  304.     LONG key;
  305.  
  306.     /* Lock the AppInfo structure */
  307.     key = LockAppInfo (ai);
  308.  
  309.     /* Get a pointer to the project node */
  310.     if (pn = (struct ProjNode *) GetTagData (APSH_ProjInfo, NULL, attrs))
  311.     {
  312.     /* Start the project */
  313.     if (start_project (ai, pn))
  314.     {
  315.         /* Add the project to our list, so that it gets freed properly */
  316.         AddTail (list, (struct Node *) pn);
  317.  
  318.         /* Adjust our project count accordingly */
  319.         p->p_NumProjs++;
  320.     }
  321.     }
  322.  
  323.     /* Remove the lock */
  324.     UnlockAppInfo (key);
  325. }
  326.  
  327.  /* Open existing project */
  328. VOID NewFunc (struct Hook *h, struct AppInfo *ai, struct AppFunction *af)
  329. {
  330.     struct ProjNode *pn;
  331.  
  332.     /* Create a new project */
  333.     DI (kprintf ("NewFunc enter\n"));
  334.     if (pn = NewProject (ai, NULL, NULL))
  335.     {
  336.     /* Start the project */
  337.     start_project (ai, pn);
  338.     }
  339.     DI (kprintf ("NewFunc exit\n"));
  340. }
  341.  
  342.  /* Close an existing project */
  343. VOID CloseFunc (struct Hook *h, struct AppInfo *ai, struct AppFunction *af)
  344. {
  345.     struct MasterData *md = (struct MasterData *) ai->ai_UserData;
  346.     struct Project *p = &(ai->ai_Project);
  347.     struct TagItem *attrs = af->af_Attrs;
  348.     struct ProjNode *pn;
  349.     struct ProjData *pd;
  350.     LONG key;
  351.  
  352.     /* Lock the master AppInfo */
  353.     key = LockAppInfo (ai);
  354.  
  355.     /* Get a pointer to the project node */
  356.     if (pn = (struct ProjNode *) GetTagData (APSH_ProjInfo, NULL, attrs))
  357.     {
  358.     /* Get the project data */
  359.     if (pd = (struct ProjData *) pn->pn_UserData)
  360.     {
  361.         /* Free the extra tags */
  362.         FreeTagItems (pd->pd_Clone);
  363.  
  364.         /* Free the project data */
  365.         FreeVec (pd);
  366.  
  367.         /* Clear the UserData field */
  368.         pn->pn_UserData = NULL;
  369.     }
  370.  
  371.     /* Set the current project */
  372.     p->p_CurProj = pn;
  373.  
  374.     /* Remove the project */
  375.     RemoveProject (ai, NULL, NULL);
  376.     }
  377.  
  378.     /* See if we should quit */
  379.     if ((p->p_NumProjs <= 0L) && !(md->md_Flags & MADF_BACKG))
  380.     {
  381.     ai->ai_Done = TRUE;
  382.     }
  383.  
  384.     /* Unlock the master AppInfo */
  385.     UnlockAppInfo (key);
  386. }
  387.  
  388.  /* One of our projects just went active */
  389. VOID ActiveToolFunc (struct Hook *h, struct AppInfo *ai, struct AppFunction *af)
  390. {
  391.     struct TagItem *attrs = af->af_Attrs;
  392.     struct ProjNode *pn;
  393.     struct ProjData *pd;
  394.     struct AppInfo *sai;
  395.     struct MsgPort *smp;
  396.     LONG key;
  397.  
  398.     /* Lock the AppInfo structure */
  399.     key = LockAppInfo (ai);
  400.  
  401.     /* Get a pointer to the project node */
  402.     if (pn = (struct ProjNode *) GetTagData (APSH_ProjInfo, NULL, attrs))
  403.     {
  404.     /* Cache the pointer to the Project data */
  405.     pd = (struct ProjData *) pn->pn_UserData;
  406.  
  407.     /* Get the address of the projects AppInfo structure */
  408.     if (sai = (struct AppInfo *) GetTagData (APSH_AppHandle, NULL, attrs))
  409.     {
  410.         /* Remember the project's AppInfo structure */
  411.         pd->pd_AI = sai;
  412.     }
  413.  
  414.     /* The address of the project's SIPC message port */
  415.     if (smp = (struct MsgPort *) GetTagData (APSH_PortAddr, NULL, attrs))
  416.     {
  417.         /* Remember the message port */
  418.         pd->pd_Port = smp->mp_Node.ln_Name;
  419.     }
  420.     }
  421.  
  422.     /* Remove the lock */
  423.     UnlockAppInfo (key);
  424. }
  425.  
  426.  /* We are already running */
  427. VOID IsActiveFunc (struct Hook *h, struct AppInfo *ai, struct AppFunction *af)
  428. {
  429.     struct MasterData *md = (struct MasterData *) ai->ai_UserData;
  430.     struct Project *p = &(ai->ai_Project);
  431.     struct List *list = &(p->p_ProjList);
  432.     struct TagItem *attrs = af->af_Attrs;
  433.     struct SIPCMessage *msg;
  434.     struct MsgPort *mp;
  435.     BOOL going = TRUE;
  436.     BOOL send = FALSE;
  437.     STRPTR port_name;
  438.  
  439.     /* Get the name of our main port */
  440.     DI (kprintf ("IsActiveFunc enter\n"));
  441.     if (port_name = (STRPTR) GetTagData (APSH_NameTag, NULL, attrs))
  442.     {
  443.     DI (kprintf("PortName: %s\n", port_name));
  444.  
  445.     /* We need a reply port */
  446.     if (mp = CreatePort (NULL, NULL))
  447.     {
  448.         /* Allocate a message */
  449.         if (msg = (struct SIPCMessage *)
  450.          AllocVec (sizeof (struct SIPCMessage), MEMF_PUBLIC | MEMF_CLEAR))
  451.         {
  452.         /* Fill out the Exec message */
  453.         msg->sipc_Msg.mn_Node.ln_Type = NT_MESSAGE;
  454.         msg->sipc_Msg.mn_Length = sizeof (struct SIPCMessage);
  455.         msg->sipc_Msg.mn_ReplyPort = mp;
  456.  
  457.         /* Fill in the SIPC message portion */
  458.         msg->sipc_Data = md->md_Tmp;
  459.         msg->sipc_DType = APSH_SDT_Command;
  460.  
  461.         /* Initialize it */
  462.         strcpy (md->md_Tmp, "SETATTRS ");
  463.  
  464.         /* See if they want us to unload */
  465.         if (ai->ai_Options[OPT_UNLOAD])
  466.         {
  467.             /* Send UNLOAD */
  468.             strcat (md->md_Tmp, "UNLOAD ");
  469.             send = TRUE;
  470.         }
  471.  
  472.         /* See if they want us to become sticky */
  473.         if (ai->ai_Options[OPT_BACKG])
  474.         {
  475.             /* Send  */
  476.             strcat (md->md_Tmp, "BACKGROUND");
  477.             send = TRUE;
  478.         }
  479.  
  480.         /* Trying to set an option? */
  481.         if (send)
  482.         {
  483.             /* Send the message */
  484.             if (SafePutToPort ((struct Message *) msg, port_name))
  485.             {
  486.             /* wait for the reply */
  487.             WaitPort (mp);
  488.  
  489.             /* Get the reply */
  490.             GetMsg (mp);
  491.             }
  492.         }
  493.         /* Make sure there are entries in the list */
  494.         else if (list->lh_TailPred != (struct Node *) list)
  495.         {
  496.             struct Node *node, *nxtnode;
  497.             struct TagItem tg[2];
  498.  
  499.             /* Prep the tag list */
  500.             tg[0].ti_Tag = APSH_ProjInfo;
  501.             tg[1].ti_Tag = TAG_DONE;
  502.  
  503.             /* Calling the Open command */
  504.             msg->sipc_Type = OpenID;
  505.  
  506.             /* Show that we're passing tags */
  507.             msg->sipc_DType = APSH_SDT_TagList;
  508.             msg->sipc_Data = tg;
  509.  
  510.             /* Let's start at the very beginning... */
  511.             node = list->lh_Head;
  512.  
  513.             /* Continue while there are still nodes */
  514.             while (going && (nxtnode = node->ln_Succ))
  515.             {
  516.             /* Remove it from this list */
  517.             Remove (node);
  518.  
  519.             /* Adjust our project count accordingly */
  520.             p->p_NumProjs--;
  521.  
  522.             /* Point to it */
  523.             tg[0].ti_Data = (ULONG) node;
  524.  
  525.             /* Send the message */
  526.             if (SafePutToPort ((struct Message *) msg, port_name))
  527.             {
  528.                 /* Wait for the reply */
  529.                 WaitPort (mp);
  530.  
  531.                 /* Pull the message */
  532.                 GetMsg (mp);
  533.             }
  534.             else
  535.             {
  536.                 /* Don't continue if the port went away */
  537.                 going = FALSE;
  538.  
  539.                 /* Set the error message */
  540.                 ai->ai_Pri_Ret = RETURN_FAIL;
  541.                 ai->ai_Sec_Ret = MPERR_NO_PORT;
  542.                 ai->ai_TextRtn =
  543.                   PrepText (ai, APSH_USER_ID, ai->ai_Sec_Ret, NULL);
  544.             }
  545.  
  546.             /* Go on to the next node */
  547.             node = nxtnode;
  548.             }
  549.         }
  550.         else
  551.         {
  552.             /* Send NEW */
  553.             strcpy (md->md_Tmp, "NEW");
  554.  
  555.             /* Send the message */
  556.             if (SafePutToPort ((struct Message *) msg, port_name))
  557.             {
  558.             /* wait for the reply */
  559.             WaitPort (mp);
  560.  
  561.             /* Get the reply */
  562.             GetMsg (mp);
  563.             }
  564.         }
  565.  
  566.         /* Free the message */
  567.         FreeVec (msg);
  568.         }
  569.  
  570.         /* Delete the reply port */
  571.         DeletePort (mp);
  572.     }
  573.     }
  574.  
  575.     DI (kprintf ("IsActiveFunc exit\n"));
  576. }
  577.  
  578. VOID SetAttrsFunc (struct Hook *h, struct AppInfo *ai, struct AppFunction *af)
  579. {
  580.     struct MasterData *md = (struct MasterData *) ai->ai_UserData;
  581.     struct Project *p = &(ai->ai_Project);
  582.     struct Funcs *f;
  583.  
  584.     if (f = af->af_FE)
  585.     {
  586.     /* Set the background bit? */
  587.     if (f->fe_Options[0])
  588.     {
  589.         md->md_Flags |= MADF_BACKG;
  590.     }
  591.  
  592.     /* Clear the background bit? */
  593.     if (f->fe_Options[1])
  594.     {
  595.         md->md_Flags &= ~MADF_BACKG;
  596.     }
  597.     }
  598.  
  599.     /* See if we should quit */
  600.     if ((p->p_NumProjs <= 0L) && !(md->md_Flags & MADF_BACKG))
  601.     {
  602.     ai->ai_Done = TRUE;
  603.     }
  604. }
  605.  
  606.  /* Shutdown routine */
  607. VOID QuitFunc (struct Hook *h, struct AppInfo *ai, struct AppFunction *af)
  608. {
  609.     struct MasterData *md = (struct MasterData *) ai->ai_UserData;
  610.     struct Project *p = &(ai->ai_Project);
  611.     extern VOID QuitForce ();
  612.     BOOL unload = FALSE;
  613.     BOOL force = FALSE;
  614.     struct Funcs *f;
  615.  
  616.     /* See if we have a parsed command */
  617.     if (f = af->af_FE)
  618.     {
  619.     /* Did they set the force switch? */
  620.     force = (BOOL) f->fe_Options[0];
  621.  
  622.     /* Are they trying to unload us? */
  623.     if (unload = (BOOL) f->fe_Options[1])
  624.     {
  625.         md->md_Flags &= ~MADF_BACKG;
  626.     }
  627.     }
  628.  
  629.     if (force)
  630.     {
  631.     /* Tell all the projects to quit */
  632.     signal_projects (ai, NULL, QuitForce);
  633.     }
  634.     else
  635.     {
  636.     /* Tell all the projects to quit */
  637.     signal_projects (ai, SIGBREAKF_CTRL_C, NULL);
  638.     }
  639.  
  640.     /* See if we should quit */
  641.     if ((p->p_NumProjs <= 0L) && !(md->md_Flags & MADF_BACKG))
  642.     {
  643.     ai->ai_Done = TRUE;
  644.     }
  645. }
  646.  
  647. VOID QuitForce (struct AppInfo * ai, struct ProjData * pd)
  648. {
  649.     /* Tell our master to open a new application */
  650.     HandlerFunc (ai,
  651.          APSH_Handler, "SIPC",
  652.          APSH_Command, AH_SENDCMD,
  653.          APSH_NameTag, pd->pd_Port,
  654.          APSH_CmdString, (ULONG) "quit force",
  655.          TAG_DONE);
  656. }
  657.  
  658.  /* Signal all projects */
  659. VOID signal_projects (struct AppInfo * ai, LONG sig, VOID (*func) (struct AppInfo *, struct ProjData *))
  660. {
  661.     struct Project *p = &(ai->ai_Project);
  662.     struct List *list = &(p->p_ProjList);
  663.     struct ProjNode *pn;
  664.     struct ProjData *pd;
  665.     LONG key;
  666.  
  667.     /* Lock the master AppInfo */
  668.     key = LockAppInfo (ai);
  669.  
  670.     /* Make sure there are entries in the list */
  671.     if (list->lh_TailPred != (struct Node *) list)
  672.     {
  673.     struct Node *node, *nxtnode;
  674.  
  675.     /* Let's start at the very beginning... */
  676.     node = list->lh_Head;
  677.  
  678.     /* Continue while there are still nodes */
  679.     while (nxtnode = node->ln_Succ)
  680.     {
  681.         pn = (struct ProjNode *) node;
  682.         pd = (struct ProjData *) pn->pn_UserData;
  683.  
  684.         if (sig)
  685.         {
  686.         /* Send a break signal to the project process */
  687.         APSHSignal (pd->pd_AI, sig);
  688.         }
  689.  
  690.         if (func)
  691.         {
  692.         (*(func)) (ai, pd);
  693.         }
  694.  
  695.         /* Go on to the next node */
  696.         node = nxtnode;
  697.     }
  698.     }
  699.  
  700.     /* Unlock the master AppInfo */
  701.     UnlockAppInfo (key);
  702. }
  703.  
  704. BOOL start_project (struct AppInfo * ai, struct ProjNode * pn)
  705. {
  706.     struct MasterData *md = (struct MasterData *) ai->ai_UserData;
  707.     struct Project *p = &(ai->ai_Project);
  708.     extern struct TagItem Project_App[];
  709.     struct ProjData *pd = NULL;
  710.     struct TagItem tg[6];
  711.     struct TagItem *clone;
  712.     BOOL retval = FALSE;
  713.     LONG key;
  714.  
  715.     /* Lock the AppInfo structure */
  716.     key = LockAppInfo (ai);
  717.  
  718.     /* Set up our tags */
  719.     tg[0].ti_Tag = APSH_AppHandle;
  720.     tg[0].ti_Data = (ULONG) ai;
  721.     tg[1].ti_Tag = APSH_ProjInfo;
  722.     tg[2].ti_Tag = APSH_PortAddr;
  723.     tg[2].ti_Data = (ULONG) md->md_SIPC;
  724.     tg[3].ti_Tag = APSH_HookClass;
  725.     tg[3].ti_Data = TRUE;
  726.     tg[4].ti_Tag = TAG_MORE;
  727.     tg[4].ti_Data = (ULONG) Project_App;
  728.     tg[5].ti_Tag = TAG_DONE;
  729.  
  730.     /* Get a pointer to the project node */
  731.     if (pn)
  732.     {
  733.     /* Set the current project */
  734.     p->p_CurProj = pn;
  735.  
  736.     /* Pass the Project node */
  737.     tg[1].ti_Data = (ULONG) pn;
  738.  
  739.     /* Clone the tag array */
  740.     if (clone = CloneTagItems (tg))
  741.     {
  742.         if (pd = (struct ProjData *) AllocVec (sizeof (struct ProjData), MEMF_CLEAR))
  743.         {
  744.         /* Remember the clone, so that we can free it */
  745.         pd->pd_Clone = clone;
  746.  
  747.         /* Attach the project data to the project node */
  748.         pn->pn_UserData = pd;
  749.  
  750.         /* Make a nice unique process name */
  751.         sprintf (md->md_Tmp, "%s.%ld", APPNAME, pn->pn_ID);
  752.  
  753.         /* Open a new project */
  754.         if (HandlerFunc (ai,
  755.                  APSH_Handler, "TOOL",
  756.                  APSH_Command, APSH_MH_OPEN,
  757.                  APSH_Tool, (ULONG) md->md_Tmp,
  758.                  APSH_ToolData, (ULONG) clone,
  759.                  TAG_DONE))
  760.         {
  761.             /* Show success */
  762.             retval = TRUE;
  763.         }
  764.         else
  765.         {
  766.             /* Unable to start the new process */
  767.             ai->ai_Pri_Ret = RETURN_FAIL;
  768.             ai->ai_Sec_Ret = MPERR_NO_PROCESS;
  769.             ai->ai_TextRtn =
  770.               PrepText (ai, APSH_USER_ID, ai->ai_Sec_Ret, NULL);
  771.         }
  772.         }
  773.         else
  774.         {
  775.         /* Free the cloned tags */
  776.         FreeTagItems (clone);
  777.  
  778.         /* Unable to allocate the project data node */
  779.         ai->ai_Pri_Ret = RETURN_FAIL;
  780.         ai->ai_Sec_Ret = MPERR_NO_MEMORY;
  781.         ai->ai_TextRtn =
  782.           PrepText (ai, APSH_USER_ID, ai->ai_Sec_Ret, NULL);
  783.         }
  784.     }
  785.     else
  786.     {
  787.         /* Not enough memory to allocate tag list */
  788.         ai->ai_Pri_Ret = RETURN_FAIL;
  789.         ai->ai_Sec_Ret = MPERR_NO_MEMORY;
  790.         ai->ai_TextRtn =
  791.           PrepText (ai, APSH_USER_ID, ai->ai_Sec_Ret, NULL);
  792.     }
  793.     }
  794.  
  795.     /* Remove the lock */
  796.     UnlockAppInfo (key);
  797.  
  798.     return (retval);
  799. }
  800.  
  801. /* Send a message to the named message port */
  802. BOOL SafePutToPort (struct Message * message, STRPTR name)
  803. {
  804.     struct MsgPort *port;
  805.  
  806.     Forbid ();
  807.  
  808.     if (port = FindPort (name))
  809.     {
  810.     PutMsg (port, message);
  811.     }
  812.  
  813.     Permit ();
  814.  
  815.     return ((BOOL) port);
  816. }
  817.